class Model{
    private _db;
    private _model;
    private _true_table_name="";
    private _fields:any=[];
    private _table_name="";
    private _options:any={
        fields:[],where:{}
    };
    private _config={
        
    }
    public static parseWhere(where){
        var w={};
        _.forOwn(where,(v,k)=>{
            if(_.isObject(v)){
                w[k]={};
                _.forOwn(v,(o,p)=>{
                    p = p.toLowerCase();
                    if(!_.isUndefined(Op[p])){
                        w[k][Op[p]]=o;
                    }else{
                        w[k][p]=o;
                    }
                })
            }else{
                w[k]=v;
            }
        })
        return w;
    }
    get config(){
        return this._config;
    }
    set config(config){
        this._config=config;
    }
    public $search={
        // "tableName":['fields']
    }

    /**
     * 构造器
     * @param Table
     * @param {string} Prefix
     */
    constructor(Table,Prefix=""){
        this._table_name=Table;
        this._true_table_name=Prefix+Table.replace(/([A-Z])/g,function ($0,$1) {
            return '_'+$1.toLowerCase();
        }).replace(/_(.+)/,"$1")
        this._db = db;
    }

    /**
     * 解析查询条件
     * @returns {{} | any}
     * @private
     */
    private _parse_where=function () {
        return this._options.where;
    }
    /**
     * 获取查询字段
     * @returns {Array}
     * @private
     */
    private _parse_fields=function () {
        if(this._options.fields.length==0){
            return Config.getTableFields(this._table_name)
        }
        return this._options.fields;
    }
    private _parse_order(){
        var order=[];
        if('string' == typeof this._options.order){
            this._options.order = this._options.order.split(',')
        }
        if(_.isArray(this._options.order)){
            _.forOwn(this._options.order,(v,k)=>{
                order.push(v.split(' '))
            })
        }
        return order;
    }
    /**
     * 解析配置文件，生成查询属性
     * @returns {{}}
     * @private
     */
    private _parse_config=function () {
        let config = {};
        config['attributes']=this._parse_fields();
        config['where']=this._parse_where();
        if(this._options.order){
            config['order']=this._parse_order()
        }
        if(this._options.limit){
            config['limit']=this._options.limit
        }
        if(this._options.offset){
            config['offset']=this._options.offset
        }
        return config;
    }
    /**
     * 设置表的字段，默认读取所有的
     * @param fields
     */
    public setTableFields=function (fields) {
        this._fields=fields;
    }
    public define=function(config={}){
        //TODO 加载数据库表结构定义
        try{
            let table = require(Config.APP_PATH+`/Db/${this._table_name}.js`)
            if(table&&table[this._table_name]){
                config = table[this._table_name];
            }
        }catch(e){
            console.log(e);
        }
        return config;
    }
    /**
     * 获取一个Sequelize的模型
     * @returns {any}
     */
    public getModel=function () {
        if(db==null){
            db = new Sequelize(Config.DATABASE.DB_NAME||"test",Config.DATABASE.DB_USER||"root",Config.DATABASE.DB_PWD||"",{
                host:Config.DATABASE.DB_HOST||"localhost",
                port:Config.DATABASE.DB_PORT||3306,
                dialect:"mysql",
                operatorsAliases:false,
                pool:{
                    max:2,
                    min:1,
                    idle:10000
                }
            });
        }
        if(!this._model){
            this._model = db.models[this._true_table_name]?db.models[this._true_table_name]:db.define(this._true_table_name, this.define(), {
                freezeTableName: true,
                timestamps: false
            })
        }
        return this._model;
    }
    public object=function () {
        
    }

    /**
     * 检测是否存在并在不存在的情况下添加数据
     * @param data
     */
    public addIfNotExist(data,where=null){
        return this.where(where||data).find().then(d=>{
            if(_.isObject(d)){
                //存在
                return true;
            }else{
                //不存在
                return this.add(data)
            }
        })
    }

    /**
     * 设定Where条件
     * @param where
     * @returns {Model.where}
     */
    public where = function (where){
        if(null == where){
            this._options.where={};
        }else
        if(_.isObject(where))
            this._options.where=Object.assign(this._options.where,where);
        else{
            console.log('Error Where',where)
        }
        return this;
    }
    /**
     * 设定字段列表，支持数组和字符串格式
     * @param {Number | String} fields
     * @param {boolean} exclude
     * @returns {Model.fields}
     */
    public fields=function (fields:Number|String,exclude=false) {
        if(_.isArray(fields)){
            this._options.fields = _.concat(this._options.fields,fields)
        }else if(_.isString(fields)){
            this._options.fields = _.concat(this._options.fields,fields.split(','))
        }
        return this;
    }
    /**
     * 设定排序规则，
     * @param {String} order
     * @returns {Model.order}
     */
    public order=function (order:String) {
        this._options.order=order;
        return this;
    }
    /**
     * 发起查询请求
     * @returns {Bluebird<any[]>}
     */
    public select=function () {
        return this.getModel().findAll(this._parse_config()).then(d=>{
            let data = [];
            this._clean();
            d.forEach(v=>{
                data.push(v.dataValues)
            })
            return data;
        });
    }
    public add=function (data) {
        return this.getModel().create(data).then(d=>{
            this._clean();
            return d.dataValues
        })
    }
    public data=function (data) {
        this.getModel().build(data)
        return this;
    }
    /**
     * 查找一个
     */
    public find=function () {
        return this.limit(1).select().then(d=>{
            this._clean();
            return d[0]
        });
    }
    /**
     * 批量添加数据
     * @param data
     * @returns {any}
     */
    public addAll=function (data) {
        return this.getModel().bulkCreate(data,{
            fields:Object.keys(data[0])
        }).then(d=>{
            this._clean();
            let data = [];
            d.forEach(v=>{
                data.push(v.dataValues)
            })
            return data;
        })
    }
    /**
     * 取数量
     */
    public count=function () {

    }
    /**
     * 支持selectAndCount
     * @returns {Promise<{count; rows: any[]}>}
     */
    public selectAndCount=function(){
        return this.getModel().findAndCountAll(this._parse_config()).then(d=>{
            let data = [];
            d.rows.forEach(v=>{
                data.push(v.dataValues)
            })
            this._clean();
            return {
                count:d.count,
                rows:data
            };
        });
    }
    /**
     * 设置limit参数，
     * @param {number} Number
     */
    public limit=function (Number:number) {
        this._options.limit=Number;
        return this;
    }
    /**
     * 设置分页参数
     * @param {number} Page
     * @param {number} Number
     * @returns {Model.page}
     */
    public page=function (p:number,n:number) {
        this._options.limit=Number(n);
        this._options.offset=(p-1)*n;
        return this;
    }
    /**
     * 调用delete语句
     * @returns {any}
     */
    public del=function () {
        return this.getModel().destroy({
            where:this._parse_where(this._options.where)
        }).then(d=>{
            this._clean();
            return d;
        })
    }
    /**
     * 调用save方法
     * @param data
     */
    public save=function (data) {
        return this.getModel().update(data,{
            where:this._parse_where(this._options.where),
            options:{
                returning:true
            }
        }).then(d=>{
            this._clean();
            return d;
        })
    }
    /**
     * 执行自定义请求
     * @param sql
     * @returns {any}
     */
    public query=function (sql) {
        return db.query(sql.replace(/__DB_PREFIX__/g,Config.DATABASE.DB_PREFIX),{
            type:Sequelize.QueryTypes.SELECT
        });
    }
    public exec=function (SQL,Type) {
        return db.query(SQL.replace(/__DB_PREFIX__/g,Config.DATABASE.DB_PREFIX,{type:Type}))
    }
    /**
     * 开启事物
     * @returns {IDBTransaction | any}
     */
    public startTrans=function () {
        return this.getModel().transaction()
    }
    /**
     * 提交
     */
    public commit=function () {
        
    }
    /**
     * 回滚
     */
    public rollback=function () {
        
    }
    /**
     * 清除查询条件，
     * @private
     */
    private _clean=function () {
        this._options.fields=[];
        this._options.where={};
        if(!_.isUndefined(this._options.limit))
            delete this._options.limit;
        if(!_.isUndefined(this._options.offset))
            delete this._options.offset;

    }

    /**
     * 获取某个字段
     * @param Fields
     * @param {boolean} More
     * @returns {any}
     */
    public getFields(Fields,More=false){
        if(!More){
            this.page(1,1)
        }
        if(_.isString(Fields)){
            Fields=Fields.split(',')
        }
        if(Fields.length>0)
            return this.fields(Fields).select().then(d=>{
                this._clean();
                var pk = Fields[0];
                if(d.length>0){
                    if(More){
                        var data = {};
                        var odata=[];
                        _.forOwn(d,(v,k)=>{
                            if(Fields.length==1){
                                odata.push(v[pk])
                            }else{
                                data[v[pk]]=v;
                            }
                        })
                        return Fields.length==1?odata:data;
                    }else{
                        if(Fields.length==1){
                            return d[0][pk];
                        }else{
                            return d[0];
                        }
                    }
                }
                return "";
            })
        else{
            return Q({})
        }
    }
}

exports.Model = Model;